/**
 * Drunk Ajax Multi Selecter
 * Created by Drunk on 15-9-15.
 * Author    :   Drunk
 * Website   :   http://drunkce.com,  http://idrunk.net
 */

var dams;
(dams = function(c){
    return new dams.prototype.init(c);
}).prototype = {
    // 初始化
    init : function(c){
        /* c = {
            wrap : '.wrap', // 列表的包含容器
            urlmode : 'http://localhost/[page].html', // url模型
            fields : { // 字段配置
                // status 字段status说明 {1 : 仅对选中项数据提交, 2 : checkbox, 4 : jumped, 8 : control}
                // value 若前缀为 fields. 则表示取其他字段值, 若非空, 则使用此值
                id : {alias : '全选', status : 2}, // 具体字段配置
                eid_name : {alias : '', value : 'fields.id'},
                bid_name : {alias : ''},
                hid_number : {alias : ''},
                status : {drunk : '<textarea drunk="variable=42,'{\'df\':\'\',\'im\':\'\',\'ipw\':\'\',\'h\':\'\',\'w\':\'100\'}'"></textarea>'},
                ctrl : {
                    alias : '',
                    buttons : [
                        {alias : ''}
                    ],
                    status : 8
                }
            }
        } */
        this.c = c;
        this.css();
        this.build();
    },
    // css初始化
    css : function(){
        if(!dams._css) dams._css = $('<style type="text/css">' +
            'table.dams{margin-top:10px;}' +
            'table.dams th{text-align:center;width:auto;}' +
            'table.dams th *{vertical-align:middle;}' +
            'table.dams td.dams-checkbox{text-align:center;}' +
            'table.dams td.align-right{text-align:right;}' +
            'table.dams td.dams-ctrl input{margin:0 2px;}' +
            '.dams-pager{margin-top:0;text-align:left;}' +
            '.dams-pager em{display:inline-block;*display:inline;*zoom:1;padding:0 6px;border:1px solid #e6e6e6;border-right:1px solid #c1c1c1;' +
            'border-bottom:1px solid #c1c1c1;color:#666;background:url(/public/style/images/repeat.gif) repeat-x;vertical-align:top;margin-left:5px;}' +
            '.dams-pager em{height:18px;line-height:18px;color:#000;cursor:pointer;}'+
            '.dams-pager em:hover{border:1px solid #002a5b;background:#00346f;text-decoration:none;color:#fff;}' +
            '.dams-pager em.a1{border:0;background:none;}' +
            '.dams-pager em.a1:hover{border:0;background:none;color:#333;}}' +
            '</style>').appendTo('body');
    },
    // 表框初始化
    build : function(){
        var me = this;
        if(!me._table){
            me._table = $('<table class="dams">').appendTo(me.c.wrap);
            me._thead = $('<tr>').appendTo($('<thead>').appendTo(me._table));
            me._tbody = $('<tbody>').appendTo(me._table);
        }
        me.buildHead();
        me.buildElem();
    },
    // 建立表头
    buildHead : function(){
        var me = this;
        me.fieldEach(function(i, j){ // head build (f means field)
            var f = me.c.fields[i];
            if(f.status & 2){ // checkbox colnum
                var eCheckbox = $('<input type="checkbox" />');
                $('<label>').append(eCheckbox).append(f.alias).appendTo($('<th>').appendTo(me._thead));
                eCheckbox.bind('change', {me: me, j: j}, function(evt){ // 全选事件
                    evt.data.me._tbody.find('tr>td:nth-child('+ (evt.data.j+1) +') :checkbox').prop('checked', $(this).is(':checked')).trigger('change');
                });
            }else{
                $('<th>'+ f.alias +'</th>').appendTo(me._thead);
            }
        });
    },
    // 字段遍历回调
    fieldEach : function(callback){
        var j = 0;
        for(var i in this.c.fields){
            if(!(this.c.fields[i].status & 4)) callback(i, j);
            j ++;
        }
    },
    // 载入列表
    load : function(page){
        page = page || 1;
        var me = this,
            url = me._urlmode.replace(/\[page\]/, page);
        dams.get(url, function(data){
            if(!data || $.isArray(data)) data = {rs:data}; // 数据格式化
            me.clear(); // 数据清除
            me.buildList(data.rs); // 建立列表
            if($.isFunction(me.c.loadcall)) me.c.loadcall(data, me); // 载入回调
            if(data.pager) me.buildPager(data.pager); // 建立分页
        });
    },
    // 清除
    clear : function(){
        this._tbody.empty();
        this._thead.find(':checked').prop('checked', false);
        if(this._pager) this._pager.empty();
    },
    // 建立列表
    buildList : function(datas){
        if(!$.isArray(datas)) datas = [];
        for(var i=0; i<datas.length; i++) this.buildRow(datas[i]);
    },
    // 建立行
    buildRow : function(data){
        var me = this,
            tr = $('<tr>').appendTo(me._tbody);
        tr[0].data = data; // 记录行数据
        me.fieldEach(function(i){
            me.buildCell(data, i, tr);
        });
    },
    // 建立格
    buildCell : function(data, i, tr){
        var me = this,
            f = me.c.fields[i],
            value = D.empty(data[i]) && f.value ? (f.value.substr(0, 7) === 'fields.' ? data[f.value.substr(7)] : f.value) : data[i]; // 处理值
        var td = $('<td data-field="'+i+'">').appendTo(tr);
        if(f.align) td.addClass('align-' + f.align);
        if(f.status & 2){ // 多选框
            var eCheckbox = $('<input type="checkbox" />').appendTo(td.addClass('dams-checkbox'));
            if(i == 'id'){
                if(!(f.status & 1)) me.check(eCheckbox, data); // 若未设置仅对选中项提交数据, 则翻页后初始化checkbox选中状态
                eCheckbox.bind('change', {me:me, data:tr[0].data}, function(evt){
                    evt.data.me.evtCheck(evt.data.data, this);
                    if($.isFunction(f.changecall)) f.changecall.call(this, evt);
                }); // 绑定check事件
            }
        }else if(f.status & 8){ // 删更控件框
            me.buildCtrl(data, i, td.addClass('dams-ctrl'));
        }else if(f.drunk){ // drunk control
            td.append($(f.drunk).val(value));
            DC.init(td);
            if(data.status & 16384) td.find('input,textarea,select').prop('disabled', true);
        }else{ // text
            td.append(value);
        }
    },
    buildCtrl : function(data, i, td){
        var me = this,
            buttons = me.c.fields[i].buttons,
            button, cb, // means button config
            j = 0;
        for(; j<buttons.length; j++){
            cb = buttons[j];
            button = $('<input type="button" value="'+cb.alias+'" />').appendTo(td);
            if($.isFunction(cb.callback)) button.bind('click', {data:data, i:i, c:me.c, b:cb}, function(e){ var d= e.data; d.b.callback(d.data, $(this))});
        }
    },
    // 建立分页
    buildPager : function(pager){
        var me = this;
        if(!me._pager){
            me._pager = $('<div class="pager dams-pager">').insertAfter(me._table);
            me._pager.delegate('em', 'click', function(){ // 翻页
                if($.isFunction(me.c.pagecall)) me.c.pagecall.call(me); // 翻页回调
                me.load($(this).attr('data-page'));
            });
        }
        me._pager.append(pager);
    },
    // 建立数据缓存表单元素
    buildElem : function(){
        var me = this;
        if(me._val) return;
        me._eVal = dams.hidden(me.c.ename, me._table); // 取存值表单元素
        var vals = me._eVal.val();
        vals = D.empty(vals) ? [] : vals.split(',');
        me._val = {};
        for(var i=0; i<vals.length; i++) me._val[vals[i]] = 1;
    },
    // 列表取值
    dataList : function(){
        var me = this,
            trs = me._tbody.children('tr'),
            data = [],
            logchecked = me.c.fields.id && (me.c.fields.id.status & 1), // 是否必选记值
            j = 0;
        trs.each(function(i, e){
            if(logchecked && !$(e).find('[data-field=id] :checked').length) return; // 如果必选记值却未选中, 则不记值
            data[j] = e.data;
            D.extend(data[j++], me.dataRow(e));
        });
        return data;
    },
    // 行取值
    dataRow : function(tr){
        var me = this,
            formTds = $(tr).children('td:has(input),td:has(textarea),td:has(select)'), // 有表单元素的td
            data = {};
        formTds.each(function(i, e){
            var td = $(e),
                cellData = me.dataCell(td);
            if(cellData === null) return;
            data[td.attr('data-field')] = cellData;
        });
        return data;
    },
    // 取表单列表项传值表单元素值
    dataCell : function(td){
        valElem = td.find('label[linkage-finally] select');
        if(!valElem.length) valElem = td.find('input:hidden');
        if(!valElem.length) valElem = td.find('input:text,textarea');
        if(valElem.length) return valElem.val();
        return null;
    },
    // checkbox状态初始化
    check : function(eCheckbox, data){
        var me = this;
        if(me._val[data.id]) eCheckbox.prop('checked', true);
    },
    // 选择器事件绑定
    evtCheck : function(data, e){
        var me = this, i, vals = [];
        e.checked ? me._val[data.id] = 1 : delete me._val[data.id];
        for(i in me._val) vals.push(i);
        me._eVal.val(vals.join(','));
        if(e.checked) $(e).closest('tr').find('input,textarea,select').prop('disabled', false); // 若有传递数据字段status, 且status&16384, 则表示该数据默认disabled, 选中单选时取消属性
    },
    // 重置值
    resetVal : function(ids){
        var me = this;
        me.buildElem();
        if(D.empty(ids)) ids = [];
        if(!$.isArray(ids)) ids = ids.split(',');
        me._eVal.val(ids.join(','));
        me._val = {};
        for(var i=0; i<ids.length; i++) me._val[ids[i]] = 1;
    },
    // 应入url关键词
    search : function(key, replacement){
        replacement = replacement || /\[search\]/;
        this._urlmode = this.c.urlmode.replace(replacement, key);
    }
};
D.extend(dams, {
    /**
     * 根据元素名取隐藏表单元素
     * @param ename string
     * @param wrap jquery
     * @param bit int       {0:insertBefore, 1:append, 2:全值复写, 4:删除传入值}
     * @param val int       保存或需删除的值
     */
    hidden : function(ename, wrap, bit, val){
        bit = D.int(bit);
        var elem = ((bit & 1) ? wrap : wrap.parent()).find('[name="'+ename+'"]');
        if(!elem.length) elem = $('<input type="hidden" name="'+ename+'" />')[(bit & 1) ? 'appendTo' : 'insertBefore'](wrap);
        if(val !== undefined) dams.val(elem, val, bit);
        return elem;
    },
    val : function(elem, val, bit){
        if(bit & 2) return elem.val($.isArray(val) ? val.join(',') : val); // 全值复写
        var value,
            vals = D.ifempty(elem.val().split(), []);
        if(!D.empty(val)){
            if(!$.isArray(val)) val = String(val).split(',');
            for(var k=0; k<val.length; k++) vals.push(val[k]); // 不管怎样先把所有的传值都压入值数组
            vals.unique();
        }
        if(bit & 4) for(var i=val.length - 1; i>=0; i--) vals.remove(val[i]); // 如果有传入4, 则表示删除
        value = val === null ? '' : vals.join(',');
        elem.val(value);
    },
    // 远程请求
    get : function(url, callback, dataType){
        $.ajax({
            url : url,
            dataType : dataType || 'jsonp',
            before : function(){},
            complete : function(){},
            success : callback
        });
    }
});
dams.prototype.init.prototype = dams.prototype;




/**
 * Auther : Your big brother Drunk
 * 动态堆叠
 * @type {{c: {increase: *[]}, init: init, add: add, del: del}}
 */
heap = {
    /*
    c : {
        // status : {1:不填则作空(即不作为表单数据提交), 2 : 不载表头, 4 : 不载控件, 8 : 记录行码值, &16 : 不初始化}
        fields : {
            start : {alias : '递增日期', status : 1, html : "<textarea class='heap-elem' drunk=\"variable=45,'{\\'ic\\':\\'1\\',\\'ts\\':\\'1\\',\\'w\\':\\'80\\',\\'t\\':\\'1\\'}'\"></textarea>"},
            // status : {&1:必填, &2:只读, &4:控件}
            quota : {alias : '递增额度', status : 1, html : "<textarea class='heap-elem' drunk=\"variable=42,'{\\'im\\':\\'\\',\\'w\\':\\'80\\'}'\"></textarea>"}
        }
    }
     */
    // 组件建立
    build : function(cc, e){
        if(!e.length) return;
        var wrap = e.empty();
        if(!$.isPlainObject(cc.event)) cc.event = {};
        e = e[0];
        if(!(cc.status & 2)){
            e.thead = $('<tr>').appendTo($('<thead>').appendTo(wrap));
            for(var j in cc.fields) e.thead.append($('<th'+ (cc.fields[j].style ? ' style="'+cc.fields[j].style+'"' : '') +'>'+ cc.fields[j].alias +'</th>'));
            if(!(cc.status & 4)) e.thead.append($('<th class="ctrl">操作</th>'));
        }
        e.tbody = $('<tbody>').appendTo(wrap);
        e.cc = cc;
        heap.apply(wrap);
        return wrap;
    },
    // 如果传入的vname为对象，则直接以其做赋取值操作
    // (新建hidden元素)? 获取/设置hidden值
    hidden : function(vname, data, listwrap){
        var elem;
        if(typeof vname === 'object'){
            elem = $(vname);
        }else{
            listwrap = listwrap || $('[heap-name]');
            elem = listwrap.parent().find('[name=\''+vname+'\']');
            if(!elem.length) elem = $('<input type="hidden" name="'+vname+'" />').insertBefore(listwrap);
        }
        return data === undefined ? elem.val() : elem.val(data);
    },
    // 数据应入表单列表
    apply : function(wrap){
        var i = 0,
            cc = wrap[0].cc,
            vname = cc.valelem || wrap.attr('heap-name'),// 若有传入对象, 则直接以此对象操作
            values = heap.hidden(vname, undefined, wrap); // 根据堆叠表格属性取表单隐藏元素值
        value_default = (cc.status & 16) ? [] : [0];
        try{values = $.parseJSON(values);} catch (e){values = value_default;}
        if(D.empty(values)) values = value_default; // 载入第一行
        if($.isFunction(cc.changecall)) cc.changecall(values, cc);
        if(!D.empty(values)) for(; i<values.length; i++) heap.add(wrap, values[i]); // 给爹初始化
        if(values.length && values[0]) wrap[0].cc.formdata = values; // 记录表单值到配置中
    },
    // 新增表单列表项
    add : function(wrap, data, index){
        var td,
            cc = wrap[0].cc,
            tbody = wrap[0].tbody,
            tr = index === undefined ? $('<tr>').appendTo(tbody) : tbody.find('>tr:eq('+index+')').empty(), // 添加 / 编辑
            trlen = heap.data(wrap);
        tr[0].data = data;
        if (!$.isPlainObject(data)) data = {};
        for (var i in cc.fields){
            td = $('<td data-name="'+ i +'"></td>').appendTo(tr);
            if(cc.fields[i].status & 2){ // 仅显示值
                td.text(cc.fields[i].summary ? data[i].summary(cc.fields[i].summary) : data[i]);
            }else if(cc.fields[i].status & 4){ // 拼装按钮
                if($.isArray(cc.fields[i].buttons)) for(var x=0; x<cc.fields[i].buttons.length; x++){
                    var btn = $('<input type="button" value="'+cc.fields[i].buttons[x].alias+'" />').appendTo(td); // 生成按钮
                    if($.isFunction(cc.fields[i].buttons[x].callback)) btn.bind('click', {wrap : wrap, tr : tr}, cc.fields[i].buttons[x].callback);
                }
            }
            if(cc.fields[i].status & 6) continue; // 仅显值或为控件

            td.html(cc.fields[i].html);
            if($.isFunction(cc.fields[i].format)) data[i] = cc.fields[i].format(data[i]); // 格式化回调
            if(data[i] !== undefined) td.find('textarea,input,select').val(data[i]);
            DC.init(td); // 组件初始化
            td.delegate(heap.getChangeSelecter(), 'change', {wrap : wrap}, heap.changeEvent); // 数据同步事件绑定
        }
        if(cc.status & 4) return; // 如果不载控件则返回咯
        var td_ctrl = $('<td class="heap-ctrl">').appendTo(tr);
        if (trlen !== 1){ // 如果不只一个tr, 则应允许删除
            td_ctrl.append($(cc.controls && cc.controls.del ? cc.controls.del : '<input type="button" value="删除" />').bind('click', {wrap : wrap, tr : tr}, heap.delEvent));
        }else{
            td_ctrl.append($(cc.controls && cc.controls.add ? cc.controls.add : '<input type="button" value="新增" />').bind('click', {wrap : wrap, tr : tr}, heap.addEvent));
        }
    },
    // 取tr index
    tr_index : function(tr){
        var index = tr.index();
        return index;
    },
    // 新增表单列表项事件处理
    addEvent : function(evt){
        var cc = evt.data.wrap[0].cc;
        if(heap.data(evt.data.wrap) !== heap.data(evt.data.wrap, 1).length) return; // 表单列表有填满才能
        heap.add(evt.data.wrap);
        if($.isFunction(cc.event.add)) cc.event.add(evt.data.wrap);
    },
    // 删除表单列表项
    delEvent : function(evt){
        var elem = $(this),
            tr = elem.closest('tr'),
            cc = evt.data.wrap[0].cc;
        if($.isFunction(cc.event.del)) cc.event.del(evt.data.wrap, heap.elemIndex(elem), tr[0].data);
        tr.remove();
        heap.sync(evt);
        if($.isFunction(cc.event.afterdel)) cc.event.afterdel(tr[0].data);
    },
    // 数据更新回调
    changeEvent : function(evt){
        var cc = evt.data.wrap[0].cc,
            olddata = cc.formdata || [];
        heap.sync(evt);
        if($.isFunction(cc.event.change)) cc.event.change(evt.data.wrap, heap.elemIndex($(this)), olddata);
    },
    elemIndex : function(elem){
        tr = D.isElem(elem, 'span') ? elem : elem.closest('tr');
        return tr.parent().children().index(tr);
    },
    // 堆叠表单列表数据同步到主表单
    sync : function(evt){
        var wrap = D.isElem(evt) ? evt : evt.data.wrap, // 如果传入的是节点, 则直接当作包裹处理同步
            data = heap.data(wrap, 1),
            vname = wrap[0].cc.valelem || wrap.attr('heap-name'); // 若有传入对象, 则直接以此对象操作
        wrap[0].cc.formdata = data; // 记录表单值到配置中
        heap.hidden(vname, D.dump(data), wrap);
    },
    // 取数据操作
    data : function(wrap, bit){
        var cc = wrap[0].cc,
            trs = wrap[0].tbody.find('tr'),
            data = [],
            needata = bit & 1;
        if (!needata) return trs.length;
        trs.each(function(i, e){
            if(!$.isPlainObject(e.data)) e.data = {}; // 全面升级啦，老数据一个不漏哦
            var val, valElem,
                elem = $(e);
            for(var j in cc.fields){
                valElem = heap.getElem(elem, j);
                if(!valElem.length) continue; // 如果无输入控件, 则表示为纯输出内容, 无需替换值且跳过
                val = heap.getDCData(valElem);
                if (D.empty(val) && cc.fields[j].status & 1) return; // 如果未输入内容且字段配置为必填, 则跳过之
                e.data[j] = val;
            }
            if(cc.status & 8) e.data.line = i+1; // 记录行码
            data[data.length] = e.data;
        });
        return data;
    },
    getDCData : function(elem){
        var hasDC = typeof DC !== 'undefined',
            isempty = hasDC ? DC.code(elem, 1) : elem.val();
        if(hasDC && isempty) elem.val('').css('color', 'black');
        return isempty ? '' : elem.val();
    },
    // 取变更事件选择器
    getChangeSelecter : function(){
        return 'input,select,textarea';
    },
    // 取表单列表项传值表单元素
    getElem : function(trelem, fname){
        var td = trelem.find('td[data-name='+fname+']'),
            valElem = td.find('.heap-elem'); // 实际表单元素为有类属性或者隐藏的元素
        if(!valElem.length) valElem = td.find('label[linkage-finally] select');
        if(!valElem.length) valElem = td.find('input:hidden');
        if(!valElem.length) valElem = td.find('input:text,textarea');
        return valElem;
    }
};